package com.xayy.health.mgt.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.kawins.base.result.CheckResult;
import cn.kawins.base.result.ResultBody;
import cn.kawins.base.utils.CollUtil;
import cn.kawins.mybatis.base.BaseServiceImpl;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;
import com.xayy.health.core.enums.*;
import com.xayy.health.mgt.mapper.TaskChildInfoMapper;
import com.xayy.health.mgt.mapper.TaskInfoMapper;
import com.xayy.health.mgt.model.FaultScoreConfig;
import com.xayy.health.mgt.model.HealthAlgorithmManage;
import com.xayy.health.mgt.model.TaskChildInfo;
import com.xayy.health.mgt.model.TaskInfo;
import com.xayy.health.mgt.model.dto.ChildTaskDto;
import com.xayy.health.mgt.model.dto.TaskInfoDto;
import com.xayy.health.mgt.model.dto.TelemetryDto;
import com.xayy.health.mgt.service.TaskChildInfoService;
import com.xayy.health.mgt.service.TaskInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Date;
import java.util.List;

/**
 * @author zhangxa
 */
@Service
public class TaskInfoServiceImpl extends BaseServiceImpl<TaskInfo> implements TaskInfoService {

    @Autowired
    private TaskInfoMapper taskInfoMapper;
    @Autowired
    private TaskChildInfoMapper taskChildInfoMapper;
    @Autowired
    private TaskChildInfoService taskChildInfoService;
    @Autowired
    private TaskInfoService taskInfoService;

    /**
     * 自动运行任务列表分页(数据处理，趋势预测，事后诊断)
     *
     * @param taskInfoDto 任务信息
     * @return 结果
     */
    @Override
    public CheckResult<?> saveTaskInfo(TaskInfoDto taskInfoDto) {
        TaskInfo taskInfo = TaskInfo.builder()
                .id(null)
                .satelliteCode(taskInfoDto.getSatelliteCode())
                .type(taskInfoDto.getType())
                .name(taskInfoDto.getName())
                .isBatch(taskInfoDto.getIsBatch())
                .build();
        insert(taskInfo);
        return CheckResult.success("保存成功");
    }

    /**
     * 自动运行任务列表分页(数据处理，趋势预测，事后诊断)
     *
     * @param taskInfoDto 任务信息
     * @return 结果日志
     */
    @Override
    public PageInfo<TaskInfo> pageList(TaskInfoDto taskInfoDto) {
        //TODO: 规范插件已经提示风险
        PageMethod.startPage(taskInfoDto.getPage(), taskInfoDto.getSize());
        List<TaskInfo> taskInfos = null;
        if (taskInfoDto.getIsBatch() == null) {
            taskInfos = taskInfoMapper.pageList(taskInfoDto);
        } else {
            taskInfos = taskInfoMapper.pageListData(taskInfoDto);
        }
        for (TaskInfo taskInfo : taskInfos) {
            CheckResult<List<HealthAlgorithmManage>> algorithmTypeByChild = taskChildInfoService.getAlgorithmTypeByChild(TaskInfo.builder().id(taskInfo.getId()).build());
            List<HealthAlgorithmManage> data = algorithmTypeByChild.getData();
            StringBuilder builder = new StringBuilder();
            if (!CollectionUtils.isEmpty(data)) {
                for (HealthAlgorithmManage algorithmManage : data) {
                    if(null!=algorithmManage.getAlgorithmType()){
                    //1 剔野 2填充 3平滑
                    if (algorithmManage.getAlgorithmType().equals(AlgorithmTypeEnum.TY.getCode())) {
                        builder.append("剔野方法:").append(algorithmManage.getAlgorithmName()).append(" ");
                    } else if (algorithmManage.getAlgorithmType().equals(AlgorithmTypeEnum.TC.getCode())) {
                        builder.append("填充方法:").append(algorithmManage.getAlgorithmName()).append(" ");
                    } else if (algorithmManage.getAlgorithmType().equals(AlgorithmTypeEnum.PH.getCode())) {
                        builder.append("平滑方法:").append(algorithmManage.getAlgorithmName()).append(" ");
                    }
                    taskInfo.setAlgorithmNameList(String.valueOf(builder));
                }

                }

            }

        }
        return new PageInfo<>(taskInfos);
    }

    /**
     * 自动运行子任务列表分页(数据处理，趋势预测，事后诊断)
     *
     * @param childTaskDto 子任务对象
     * @return 结果日志
     */
    @Override
    public PageInfo<TaskChildInfo> getChildTaskPageList(ChildTaskDto childTaskDto) {
//TODO: 规范插件已经提示风险
        PageMethod.startPage(childTaskDto.getPage(), childTaskDto.getSize());
        List<TaskChildInfo> taskChildInfos = taskChildInfoMapper.getChildTaskPageList(childTaskDto);
        return new PageInfo<>(taskChildInfos);
    }

    /**
     * 修改信息状态信息
     *
     * @param telemetryDto 信息信息
     */
    @Override
    public void updateStatusByTaskInfo(TelemetryDto telemetryDto) {
        // 修改status失效状态
        TaskInfo taskInfo = Convert.convert(TaskInfo.class, telemetryDto);
        taskInfo.setParams(ArrayUtil.join(telemetryDto.getParamCodes(), ","));
        Example example = new Example(TaskInfo.class);
        taskInfo.setStatus(TaskInfoStatusEnum.STOP.getStatusCode());
        example.createCriteria().andEqualTo("name", taskInfo.getName())
                .andEqualTo("satelliteCode", taskInfo.getSatelliteCode()).andEqualTo("params", taskInfo.getParams());
        taskInfoMapper.updateByExample(taskInfo, example);

    }

    /**
     * 事后诊断上线运行
     *
     * @param telemetryDto 遥测入参
     * @return ResultBody
     */
    @Override
    public ResultBody online(TelemetryDto telemetryDto) {
        /*查询任务信息*/
        List<TaskInfo> infoList = taskInfoService.select(TaskInfo.builder().satelliteCode(telemetryDto.getSatelliteCode()).name(telemetryDto.getName()).type(SystemModelTypeEnum.POST_HOC_DIAGNOSIS.getSystemModelTypeCode()).build());
        if (!infoList.isEmpty()) {
            return ResultBody.failed("任务名称与任务列表中重复,请修改任务名称");
        }
        /*校验如果选择了处理后的数据需要判断时间和间隔
        * 1.检测开始时间不能早预处理时间
        * 2.轮询周期需要大于预处理周期
        */
        if(telemetryDto.getOriginalDataSources() == 1){
            String msg = checkCycleAndTime(telemetryDto);
            if(msg != null){
                return ResultBody.failed(msg);
            }
        }
        TaskInfo taskInfo = Convert.convert(TaskInfo.class, telemetryDto);
        taskInfo.setName(telemetryDto.getSatelliteCode() + "_" + DateUtil.format(telemetryDto.getStartTime(), "yyyyMMddHHmmss"));
        taskInfo.setAlgorithmName(telemetryDto.getAlgorithmName());
        taskInfo.setStatus(1);
        if (telemetryDto.getCompare() != null) {
            taskInfo.setCompare(telemetryDto.getCompare().toString());
        }
        taskInfo.setParamCodeName(telemetryDto.getParamCodeName());
        taskInfo.setMultiparameterAlgName(telemetryDto.getMultiparameterAlgName());
        taskInfo.setName(telemetryDto.getName());
        taskInfo.setParams(telemetryDto.getParamCode());
        taskInfo.setIsCurrentParams(telemetryDto.getIsCurrentParams());
        taskInfo.setType(SystemModelTypeEnum.POST_HOC_DIAGNOSIS.getSystemModelTypeCode());
        taskInfo.setRunningStatus(telemetryDto.getRunningStatus());


        if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.LONG_RUNNING.getCode())) {
            taskInfo.setLongRunningTime(telemetryDto.getStartTime());
            taskInfo.setEndTime(null);

        } else if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.RUN_IN_STAGES.getCode())) {
            taskInfo.setRunInStagesTime(telemetryDto.getEndTime());
            taskInfo.setEndTime(taskInfo.getStartTime());
        }
        //是否为多参
        if (!telemetryDto.getCheckMultiparameter()) {
          oneParam(taskInfo, telemetryDto);
        } else {
          manyParam(taskInfo, telemetryDto);
        }
        return ResultBody.success("任务" + telemetryDto.getName() + "上线成功");
    }

    /**
     * 多参数线上运行处理
     */
    private void manyParam(TaskInfo taskInfo, TelemetryDto telemetryDto) {
        if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.LONG_RUNNING.getCode())) {
            taskInfo.setEndTime(null);
            taskInfo.setLongRunningTime(telemetryDto.getStartTime());
        } else if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.RUN_IN_STAGES.getCode())) {
            taskInfo.setEndTime(taskInfo.getStartTime());
            taskInfo.setRunInStagesTime(telemetryDto.getEndTime());
        }
        //多参
        taskInfo.setCheckMultiparameter(1);
        if (telemetryDto.getMultiparameterAlgName().equals(MultiParameterEnum.SLOPEALGORITHM.getCode()) || telemetryDto.getMultiparameterAlgName().equals(MultiParameterEnum.KNEARESTNEIGHBORALGORITHM.getCode())) {
            taskInfoService.insert(taskInfo);
        } else if (telemetryDto.getMultiparameterAlgName().equals(MultiParameterEnum.MEANFEATUREALGORITHM.getCode())) {
            taskInfo.setPointNum(telemetryDto.getPointNum());
            taskInfo.setSampleTime(telemetryDto.getSampleTime());
            taskInfo.setIntervalNum(telemetryDto.getInterval());
            taskInfo.setProbability(telemetryDto.getProbability());
            taskInfoService.insert(taskInfo);
        } else if (telemetryDto.getMultiparameterAlgName().equals(MultiParameterEnum.TWOPARAMETERDIAGNOSISALGORITHM.getCode())) {
            taskInfo.setNormalStartTime(telemetryDto.getNormalStartTime());
            taskInfo.setNormalEndTime(telemetryDto.getNormalEndTime());
            taskInfoService.insert(taskInfo);
        } else if (telemetryDto.getMultiparameterAlgName().equals(MultiParameterEnum.THRESHOLDJUDGMENTALGORITHM.getCode())) {
            taskInfo.setThreshold(telemetryDto.getThreshold());
            taskInfoService.insert(taskInfo);
        }
    }

    /**
     * 单参数线上运行处理
     */
    private void oneParam(TaskInfo taskInfo, TelemetryDto telemetryDto) {
        //案例一
        if (telemetryDto.getIsCallModel() == 0) {
            taskInfo.setStartTime(telemetryDto.getVerifyTime().getStartTime());
            DateTime endTime = DateUtil.offsetMinute(telemetryDto.getVerifyTime().getStartTime(), (int) (Double.parseDouble(telemetryDto.getCycle()) * 60));
            taskInfo.setDeviate(telemetryDto.getDeviate());
            taskInfo.setLearnMultiTerminalTime(taskInfo.getLearnMultiTerminalTime());
            taskInfo.setIsCaseOne(0);
            taskInfo.setIsFirst(1);
            if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.LONG_RUNNING.getCode())) {
                taskInfo.setEndTime(null);
                taskInfo.setLongRunningTime(endTime);
            } else if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.RUN_IN_STAGES.getCode())) {
                taskInfo.setEndTime(taskInfo.getStartTime());
                taskInfo.setRunInStagesTime(telemetryDto.getVerifyTime().getEndTime());
            }

        } else {
            //单参模型
            taskInfo.setCheckMultiparameter(0);
            taskInfo.setIsCaseOne(1);
            if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.LONG_RUNNING.getCode())) {
                taskInfo.setLongRunningTime(telemetryDto.getStartTime());
                taskInfo.setEndTime(null);
            } else if (telemetryDto.getRunningStatus().equals(RunningStatusEnum.RUN_IN_STAGES.getCode())) {
                taskInfo.setEndTime(taskInfo.getStartTime());
                taskInfo.setRunInStagesTime(telemetryDto.getEndTime());
            }

        }
        taskInfoService.insert(taskInfo);
    }

    private String checkCycleAndTime(TelemetryDto telemetryDto) {
        /*单参数*/
        if (!telemetryDto.getCheckMultiparameter()) {
            /*构建查询条件*/
            Example example = new Example(TaskInfo.class);
            Example.Criteria criteria = example.createCriteria();
            example.orderBy("startTime").desc();
            criteria.andLike("params",telemetryDto.getParamCode());
            criteria.andEqualTo("satelliteCode",telemetryDto.getSatelliteCode());
            criteria.andLike("type","1");
            List<TaskInfo> taskInfos = selectByExample(example);
            if(CollUtil.isNotEmpty(taskInfos)){
                TaskInfo taskInfo = taskInfos.get(0);
                /*如果事后诊断的开始时间在预处理之前，则给出提示*/
                if(telemetryDto.getStartTime().before(taskInfo.getStartTime())){
                    return "检测开始时间不能早预处理时间【"+taskInfo.getStartTime()+"】";
                }
                /*如果周期小于预处理周期则给出提示*/
                if(Integer.parseInt(taskInfo.getCycle()) > Integer.parseInt(telemetryDto.getCycle())){
                    return "轮询周期不能小于预处理周期【"+taskInfo.getCycle()+"小时】";
                }
            }
        }else{
            /*多参数*/
            String[] split = telemetryDto.getParamCode().split(",");
            Date maxTime = null;
            Integer maxCycle = null;
            /*循环多参数，查询出最大时间的周期和最大的时间*/
            for (String paramCode : split) {
                Example example = new Example(TaskInfo.class);
                Example.Criteria criteria = example.createCriteria();
                example.orderBy("startTime").desc();
                criteria.andLike("params",paramCode);
                criteria.andEqualTo("satelliteCode",telemetryDto.getSatelliteCode());
                criteria.andLike("type","1");
                List<TaskInfo> taskInfos = selectByExample(example);
                if(CollUtil.isNotEmpty(taskInfos)) {
                    TaskInfo taskInfo = taskInfos.get(0);
                    if(maxTime == null){
                        maxTime = taskInfo.getStartTime();
                    }else{
                        if(maxTime.before(taskInfo.getStartTime())){
                            maxTime = taskInfo.getStartTime();
                        }
                    }
                    if(maxCycle == null){
                        maxCycle = Integer.parseInt(taskInfo.getCycle());
                    }else{
                        if(maxCycle < Integer.parseInt(taskInfo.getCycle())){
                            maxCycle = Integer.parseInt(taskInfo.getCycle());
                        }
                    }
                }
            }
            /*如果事后诊断的开始时间在预处理之前，则给出提示*/
            if(maxTime != null && telemetryDto.getStartTime().before(maxTime)){
                return "检测开始时间不能早预处理时间【"+maxTime+"】";
            }
            /*如果周期小于预处理周期则给出提示*/
            if(maxCycle != null && maxCycle > Integer.parseInt(telemetryDto.getCycle())){
                return "轮询周期不能小于预处理周期【"+maxCycle+"小时】";
            }
        }
        return null;
    }

    /**
     * 获取数据预处理任务信息
     *
     * @param taskInfo 任务信息
     * @return List<TaskInfo>
     */
    @Override
    public List<TaskInfo> selectPreData(TaskInfo taskInfo) {
        return taskInfoMapper.selectPreData(taskInfo);
    }

    /**
     * 根据任务id查询任务数据
     *
     * @param taskId 任务id
     * @return CheckResult<TaskInfo>
     */
    @Override
    public CheckResult<TaskInfo> selectTaskInfo(Long taskId) {
        if (taskId != null) {
            return CheckResult.success(taskInfoService.selectOne(TaskInfo.builder().id(taskId).build()));
        } else {
            return CheckResult.fail("任务id不能为空");
        }
    }
}
